
(* Fenetre Principale *)

let window =
  ignore(GMain.init ());
  let wnd = GWindow.window
    ~title:"Roc N Roll"
    ~position:`CENTER
    ~resizable:true
    ~width:1200 ~height:600 () in
  ignore (wnd#connect#destroy GMain.quit);
  wnd

(* Box Principale *)
    
let vbox = GPack.vbox 
  ~spacing:5
  ~border_width:5
  ~packing:window#add ()

(* Toolbar *)

let toolbar = GButton.toolbar  
  ~orientation:`HORIZONTAL  
  ~style:`BOTH
  ~packing:(vbox#pack ~expand:false) ()

(* Box Cadres *)

let hbox = GPack.hbox
  ~spacing:5
  ~border_width:5
  ~packing:vbox#add ()

(* Box Image *)

let scroll_image = GBin.scrolled_window
  ~border_width:5
  ~shadow_type:`ETCHED_IN
  ~packing:hbox#add ()

let image = GMisc.image
  ~packing:scroll_image#add_with_viewport ()

(* Box Texte *)

let box = GPack.vbox
  ~spacing:5
  ~packing:(hbox#pack ~expand:true) ()

let scroll = GBin.scrolled_window
  ~border_width:5
  ~hpolicy:`AUTOMATIC
  ~vpolicy:`AUTOMATIC
  ~shadow_type:`IN
  ~packing:(box#pack ~expand:true)  ()
  
let text = GText.view
  ~packing:scroll#add
  ~wrap_mode:`WORD ()

let file_name = ref ""

let load file =
  begin
    image#set_file file;
    file_name := file;
  end

let open_action stock event action =
  let dlg = GWindow.file_chooser_dialog
    ~title:"Ouvrir un nouveau fichier"
    ~action:`OPEN
    ~parent:window
    ~position:`CENTER_ON_PARENT
    ~destroy_with_parent:true () in
  dlg#add_button_stock `CANCEL `CANCEL;
  dlg#add_select_button_stock `OPEN event;
  let btn = GButton.tool_button
    ~stock: `NEW
    ~packing:toolbar#insert () in
  ignore (btn#connect#clicked (fun () ->
				 if dlg#run () = `OPEN then Gaux.may action
 dlg#filename;
				 dlg#misc#hide ()));
  btn

let open_button = open_action `OPEN `OPEN load

let val2string = function
  |0 -> "A"
  |1 -> "B"
  |2 -> "C"
  |3 -> "D"
  |4 -> "E"
  |5 -> "F"
  |6 -> "G" 
  |7 -> "H"
  |8 -> "I"
  |9 -> "J"
  |10 -> "K"
  |11 -> "L"
  |12 -> "M"
  |13 -> "N"
  |14 -> "O"
  |15 -> "P"
  |16 -> "Q"
  |17 -> "R"
  |18 -> "S"
  |19 -> "T"
  |20 -> "U"
  |21 -> "V"
  |22 -> "W"
  |23 -> "X"
  |24 -> "Y"
  |25 -> "Z"
  |_ -> "."

let networkProcess img =
  let list_seg = ref [] in
  let list_string = ref [] in
  begin
    list_seg := Segmentation.segmentation img img false;
    let rec parc = function
      |[] -> ()
      |(Segmentation.Return)::l -> begin
	list_string := ("\n")::(!list_string);
	parc l;
	end
      |(Segmentation.Space)::l -> begin
	list_string := (" ")::(!list_string);
	parc l;
	end
      |(Segmentation.Img i)::l -> begin
	Sdlvideo.save_BMP i "img";
	let pb = GdkPixbuf.from_file_at_size "img" 20 20 in
	GdkPixbuf.save "img" "bmp" pb;
	let imgNeuron = Sdlloader.load_image "img" in
	list_string := (val2string(Neuronal.network imgNeuron 0
 false))::(!list_string);
	parc l;
      end in
    parc !list_seg;
  end;
  !list_string

let process img = 
  begin
    if not(Sys.file_exists "weights") then
      begin
	for i = 0 to 1000 do
	  for j = 0 to 25 do
	    let img2 = Sdlloader.load_image (Printf.sprintf("chars/%d.bmp")
 (j)) in
	    let x = ref 0 in
	    x := Neuronal.network img2 j true;
	    print_int(i);
	    print_newline();
	  done;
	done;
      end
    else
      begin
	let list = networkProcess img in
	let file = open_out "textOutput" in
	let rec parc list = match list with
	  |[] -> close_out file;
	  |s::l -> begin
	    output_string file s;
	    parc l;
	  end in
	parc list;
      end
  end;
  "textOutput"

let execute_action file_name = 
  let ich = open_in (process (Sdlloader.load_image (file_name))) in 
  let len = in_channel_length ich in 
  let buf = Buffer.create len in 
  Buffer.add_channel buf ich len;
  close_in ich;
  text#buffer#set_text (Buffer.contents buf)

let execute_button = 
  let btn = GButton.tool_button
  ~stock:`EXECUTE
  ~packing:toolbar#insert () in 
  btn#connect#clicked (fun () -> execute_action !file_name)
    
(* Sauvegarder *)

let saved = ref false

let save (text : GText.view) file =
  let och = open_out file in
  output_string och (text#buffer#get_text ());
  saved := true;
  close_out och

let save_action stock event action =
  let dlg = GWindow.file_chooser_dialog
    ~title:"Enregistrer ce texte"
    ~action:`SAVE
    ~parent:window
    ~position:`CENTER_ON_PARENT
    ~destroy_with_parent:true () in
  dlg#add_button_stock `CANCEL `CANCEL;
  dlg#add_select_button_stock stock event;
  let btn = GButton.tool_button
    ~stock
    ~packing:toolbar#insert () in
  ignore (btn#connect#clicked (fun () ->
				 if dlg#run () = `SAVE then Gaux.may action
 dlg#filename;
				 dlg#misc#hide ()));
  btn

let save_button = save_action `SAVE `SAVE (save text)

let separator = GButton.separator_tool_item
  ~packing:toolbar#insert ()

(* Zoom In/Zoom Out *)

let zoom scale =
  let s = scale in
  let pb0 = image#pixbuf in
  let w = int_of_float (float (GdkPixbuf.get_width pb0) *. s) in
  let h = int_of_float (float (GdkPixbuf.get_height pb0) *. s) in
  let pb = GdkPixbuf.from_file_at_size !(file_name) w h in
  image#set_pixbuf pb

let zoomin _ =
  if(!file_name <> "") then
    zoom 1.1
  else ()

let zoomout _ =
  if(!file_name <> "") then
    zoom 0.9
  else ()

let zoom_in =
  let zi = GButton.tool_button
    ~stock:`ZOOM_IN
    ~packing:toolbar#insert () in
  ignore(zi#connect#clicked ~callback:zoomin);
  zi

let zoom_out =
  let zo = GButton.tool_button
    ~stock:`ZOOM_OUT
    ~packing:toolbar#insert () in
  ignore(zo#connect#clicked ~callback:zoomout);
  zo

let zoom_reset _ =
  if(!file_name <> "") then
    image#set_file !file_name
  else ()

let zoom_res =
  let zreset = GButton.tool_button
    ~stock:`ZOOM_100
    ~label:"Zoom 100%"
    ~packing:toolbar#insert () in
  ignore(zreset#connect#clicked ~callback:zoom_reset);
  zreset

let separator = GButton.separator_tool_item
  ~packing:toolbar#insert ()

(* Spell Check *)

let languages = [ "fr_FR"; "en_US" ]

let report_error text msg =
  let message = "<b><big>GtkSpell error:</big></b>\n" ^ (Glib.Markup.escape_text msg) in
  let dlg = GWindow.message_dialog
    ~message ~use_markup:true ~message_type:`ERROR ~buttons:GWindow.Buttons.close
    ?parent:(GWindow.toplevel text) ~destroy_with_parent:true () in
  ignore (dlg#run ()) ;
  dlg#destroy ()

let set_lang_cb text lang =
  prerr_endline "GtkSpell.set_language" ;
  try GtkSpell.set_language text lang ; true
  with GtkSpell.Error (_, msg) -> report_error text msg ; false

type button_state = {
  mutable lang_id : int ;
  mutable error : bool
}

let build_language_list text packing =
  let (combo, _) as c = GEdit.combo_box_text ~strings:languages ~packing () in
  let state = { lang_id = -1 ; error = false } in
  ignore (combo#connect#changed
	    (fun () ->
	       if state.error
	       then state.error <- false
	       else
		 if set_lang_cb text (GEdit.text_combo_get_active c)
		 then state.lang_id <- combo#active
		 else begin
		   state.error <- true ;
		   combo#set_active state.lang_id
		 end)) ;
  c

let attach_cb button text lang_list () =
  try
    if button#active
    then begin
      prerr_endline "GtkSpell.attach" ;
      GtkSpell.attach ?lang:(GEdit.text_combo_get_active lang_list) text end
    else begin
      prerr_endline "GtkSpell.detach" ;
      GtkSpell.detach text end
  with GtkSpell.Error (_, msg) ->
    button#set_active false ;
    report_error text msg

let setup packing =
  let hbox_buttons = GPack.button_box `HORIZONTAL ~spacing:0 ~packing:box#pack ~layout:`EDGE () in
  let attached = GButton.toggle_button ~stock:`SPELL_CHECK ~packing:hbox_buttons#pack () in
  let lang_list = build_language_list text (hbox_buttons#pack ~from:`END) in
  ignore (attached#connect#toggled (attach_cb attached text lang_list)) ;
  ()

let help_button =
  let dlg = GWindow.message_dialog
    ~message:"<b>Merci d\'utiliser RocNRoll</b>.\n
Pour reconnaitre le texte d'une image, suivez les instructions suivantes : \n
1 - Cliquez sur <b>Nouveau</b> pour ouvrir un nouveau fichier.\n
2 - Choisissez une image (formats autorises :<i> .jpg, .png, .bitmap, .gif et .tif</i>) et cliquez sur <b>Ouvrir</b>. L'image devrait apparaitre dans la zone de gauche.\n
3 - Cliquez ensuite sur <b>Executer</b> pour lancer l'exexucution de la reconnaissance des caracteres.\n
4 - Lorsque le texte reconnu est apparu dans la zone de texte de droite, vous pouvez corriger les eventuelles erreurs en activant la <b>Verification Orthographique</b> et en faisant clic-droit sur les mots soulignes en rouge.\n
5 - Cliquez sur <b>Enregistrer</b> pour enregisrer le texte obtenu dans un fichier au format .txt\n

Des commandes de zoom sont a votre disposition pour zoomer/dezoomer sur l'image."
    ~title:"Aide"
    ~parent:window
    ~destroy_with_parent:true
    ~use_markup:true
    ~message_type:`QUESTION
    ~position:`CENTER_ON_PARENT
    ~buttons:GWindow.Buttons.close()
  in
  let btn = GButton.tool_button
    ~stock:`HELP
    ~packing:toolbar#insert ()
  in
  ignore(btn#connect#clicked (fun () -> ignore (dlg#run ());
             dlg#misc#hide ()));
  btn

let about_button =
  let dlg = GWindow.about_dialog
    ~name:"RocNRoll"
    ~authors:["Mindustries";
          "LOUSTAUNAU Adrien";
          "THUAULT Clement";
          "BENCTEUX Jeffrey";
          "MAREE Mathieu"]
    ~copyright:"Copyright 2012-2013 Mindustries"
    ~icon_name:"test_logo.jpg"
    ~version:"1.0"
    ~website:"http://www.alpha14/rocnroll/"
    ~website_label:"www.rocnroll.fr"
    ~position:`CENTER_ON_PARENT
    ~parent:window
    ~destroy_with_parent:true () in
  dlg#set_logo(GdkPixbuf.from_file "test_logo.jpg");
  let btn = GButton.tool_button  
    ~stock:`ABOUT
    ~packing:toolbar#insert () in
  ignore (btn#connect#clicked (fun () -> ignore (dlg#run ()); dlg#misc#hide ()));
  btn

let confirm _ = 
   let dlg = GWindow.message_dialog
      ~title:"Quitter?"
      ~message:"<b><big>Voulez-vous vraiment quitter?</big></b>\n\n\
      Attention :\nToute modification non enregistree sera perdue.\n"
      ~parent:window
      ~destroy_with_parent:true
      ~use_markup:true
      ~message_type:`QUESTION
      ~position:`CENTER_ON_PARENT
      ~buttons:GWindow.Buttons.yes_no () in
    let res = dlg#run () = `NO in
    dlg#destroy ();
    res
  
let initinterface () = 
  ignore (window#event#connect#delete confirm);
  setup box#add;
  window#show ();
  GMain.main ()

let main () =
  begin
    let b = ref false and g = ref false and n = ref false and s = ref false
    and r = ref false and p = ref false and a = ref 0. in
      begin
	if (Array.length(Sys.argv) < 2) then
	  begin
	    initinterface ();
	  end
        else if (Array.length(Sys.argv) < 3) then
	  begin
	  match Sys.argv.(1) with
	    |"--help" -> begin 
	      print_string("Usage : filepath commands [arg]");
	      print_newline();
	      print_string("Type -help command to obtain help");
	      print_string(" on a specific command.");
	      print_newline();
	      print_string("Available options :");
	      print_newline();
	      print_string("-g"); print_newline();
	      print_string("-n"); print_newline();
	      print_string("-b"); print_newline();
	      print_string("-r"); print_newline();
	      print_string("-s"); print_newline();
	      print_string("-p"); print_newline();
	      print_string("--help"); print_newline();
	    end
	    |_ -> failwith ("Specify a valid file path and a command, or type --help to display the list of options");
	  end
	else if (Array.length(Sys.argv) = 3) then
	  begin
	  match Sys.argv.(1) with
	    |"-help" -> begin match Sys.argv.(2) with
		          |"-g" -> print_string("-g : Grayscales the picture");
			    print_string(" (0 to 255 RGB value).");
			    print_newline();
			  |"-b" -> print_string("-b : Binarizes the picture");
			    print_string(" (0 or 255 RGB value).");
			    print_newline();
		          |"-n" -> print_string("-n : Reduces the noise with");
			    print_string(" a relaxed median filter.");
			    print_newline();
			  |"-r" -> print_string("-r [d]: Rotates the picture");
			    print_string(" of d degrees, or detects the angle");
			    print_string(" if not specified");
			    print_newline();
                          |"-s" -> print_string("-s : Segmentates the given");
			    print_string(" picture and detects text areas");
			    print_string(" and characters.");
			    print_newline();
			  |"-p" -> print_string("-p : Processes the given");
			    print_string(" picture and gives the detected");
			    print_string(" text output.");
			    print_newline();
			  |_ -> failwith ("Invalid command.");
	                end
	    |"-g"|"-b"|"-n"|"-r"|"-s" -> failwith ("Specify a picture first.");
	    |_ -> begin match Sys.argv.(2) with
		          |"-g" -> g := true;
			  |"-b" -> b := true;
		          |"-n" -> n := true;
			  |"-r" -> r := true;
                          |"-s" -> s := true;
			  |"-p" -> p := true;
			  |_ -> failwith ("Invalid command.");
	                end
	  end
	else if (Array.length(Sys.argv) > 3) then
          begin
	    match Sys.argv.(1) with
	      |"-help" -> failwith("Invalid command.");
	      |"-g"|"-b"|"-n"|"-r"|"-s"|"-p" -> failwith("Specify a picture first.");
	      |_ -> begin for i = 2 to Array.length(Sys.argv) -2 do
			    begin match Sys.argv.(i) with
				|"-g" -> g := true;
				|"-b" -> b := true;
				|"-n" -> n := true;
				|"-r" -> r := true;
				|"-s" -> s := true;
				|"-p" -> p := true;
				|_ -> failwith ("Invalid command.");
			    end;
		          done;
		            begin match Sys.argv.(Array.length(Sys.argv)-1)
			      with
				|"-g" -> g := true;
				|"-b" -> b := true;
				|"-n" -> n := true;
				|"-r" -> r := true;
				|"-s" -> s := true;
				|"-p" -> p := true;
				|_ -> a := float_of_string(Sys.argv.
						    (Array.length(Sys.argv)-1));
			    end
	            end
	  end
      end;

    if (!g || !b || !n || !r || !s || !p) then
      begin
	Preprocess.sdl_init ();
	let img = Sdlloader.load_image Sys.argv.(1) in
	let (w,h) = Preprocess.get_dims img in
        let display = Sdlvideo.set_video_mode w h [`DOUBLEBUF] in
	Preprocess.show img display;
	Preprocess.wait_key ();
	let scr = ref 0 in
	let dst = Sdlvideo.create_RGB_surface_format img [] w h in
	let dst2 = Sdlvideo.create_RGB_surface_format img [] w h in
	let dst3 = Sdlvideo.create_RGB_surface_format img [] w h in
	begin
	  if !g then
	    begin
	      Preprocess.image2grey img dst;
	      scr := !scr+1;
	    end;
	  if !n then
	    begin
	      match !scr with
		|0 -> Preprocess.noise img img;
		|1 -> Preprocess.noise dst dst;
		|_ -> ();
	    end;
	  if !b then
	    begin
	      match !scr with
		|0 -> Preprocess.binarize img dst
		  (Preprocess.otsu img (Preprocess.histogram img));scr :=
 !scr+1;
		|1 -> Preprocess.binarize dst dst2
		  (Preprocess.otsu dst (Preprocess.histogram dst));scr :=
 !scr+1;
		|_ -> ();
	    end;
	  if !r then
	    begin
	      if !a = 0. then
		begin
		  match !scr with
		    |0 -> a := Rotation.angle img;
		    |1 -> a := Rotation.angle dst;
		    |2 -> a := Rotation.angle dst2;
		    |_ -> ();
		end;
	      a := !a *. 0.0174532925;
	      match !scr with
		|0 -> begin
		  for i = 0 to w-1 do
		    for j = 0 to h-1 do
		      Sdlvideo.put_pixel_color dst i j (255,255,255);
		    done;
		  done;
		  Rotation.rotate img dst (!a);
		  scr := !scr+1;
	        end
		|1 -> begin
		  for i = 0 to w-1 do
		    for j = 0 to h-1 do
		      Sdlvideo.put_pixel_color dst2 i j (255,255,255);
		    done;
		  done;
		  Rotation.rotate dst dst2 (!a);
		  scr := !scr+1;
	        end
		|2 -> begin
		  for i = 0 to w-1 do
		    for j = 0 to h-1 do
		      Sdlvideo.put_pixel_color dst3 i j (255,255,255);
		    done;
		  done;
		  Rotation.rotate dst2 dst3 (!a);
		  scr := !scr+1;
	        end
		|_ -> ();

	    end;
	  if !s then
	    begin
	      let list_seg = ref [] in
	      begin
		match !scr with
		  |0 -> list_seg := Segmentation.segmentation img img true;
		  |1 -> list_seg := Segmentation.segmentation dst dst true;
		  |2 -> list_seg := Segmentation.segmentation dst2 dst2 true;
		  |3 -> list_seg := Segmentation.segmentation dst3 dst3 true;
		  |_ -> ();
	      end;
	    end;
	  if !p then
	    begin
	      let in_channel = open_in (process img) in
	      try
		while true do
		  let line = input_line in_channel in
		  begin
		    print_string (line);
		    print_newline();
		  end
		done;
	      with End_of_file ->
		close_in in_channel;
	    end;
	  match !scr with
	    |0 -> Preprocess.show img display; Preprocess.wait_key ();
	    |1 -> Preprocess.show dst display; Preprocess.wait_key ();
	    |2 -> Preprocess.show dst2 display; Preprocess.wait_key ();
	    |3 -> Preprocess.show dst3 display; Preprocess.wait_key ();
	    |_ -> ();
	end;
      end;
    exit 0
  end

let _ = main ()
